from decimal import ROUND_HALF_UP, Decimal, InvalidOperation
from django.utils import timezone
from django.db import models,transaction  
from django.core.validators import MinValueValidator
from django.forms import ValidationError
from apps.accounts.models import User
from apps.chefs.models import DjChef
from apps.schedules.models import TimeSlot
from .services.order_service import OrderNumberGenerator
from django.utils.translation import gettext_lazy as _
import logging
logger = logging.getLogger(__name__)
# 状态映射关系（Order -> DjChefOrder）
ORDER_TO_CHEF_STATUS = {
    'paid': 'pending',          # 用户支付后，厨师订单变为待确认
    'confirmed': 'confirmed',   # 用户订单确认后，厨师订单同步确认
    'cancelled': 'cancelled',   # 用户订单取消后，厨师订单同步取消
    'completed': 'completed',   # 用户订单完成后，厨师订单同步完成
    'refunded': 'cancelled',    # 用户订单退款后，厨师订单同步取消
}

# 状态映射关系（DjChefOrder -> Order）
CHEF_TO_ORDER_STATUS = {
    'pending': 'paid',          # 厨师订单待确认时，用户订单应为已支付
    'confirmed': 'confirmed',   # 厨师订单确认后，用户订单同步确认
    'cancelled': 'cancelled',   # 厨师订单取消后，用户订单同步取消
    'completed': 'completed',   # 厨师订单完成后，用户订单同步完成
    'serving': 'confirmed',     # 厨师服务中时，用户订单保持已确认（可根据业务调整）
}


class Order(models.Model):
    STATUS_CHOICES = (
        ('pending', '待支付'),
        ('paid', '已支付'),
        ('confirmed', '已确认'),
        ('completed', '已完成'),
        ('cancelled', '已取消'),
        ('refunded', '已退款')
    )
    
    PAYMENT_METHODS = (
        ('wechat', '微信支付'),
        ('alipay', '支付宝'),
        ('balance', '余额支付')
    )

    # 关系字段
    customer = models.ForeignKey(User, on_delete=models.PROTECT, related_name='orders')
    chef = models.ForeignKey(DjChef, on_delete=models.PROTECT, related_name='orders')
    address = models.ForeignKey('address.Address', on_delete=models.PROTECT)

    # 微信相关字段
    wechat_pay_transaction_id = models.CharField(max_length=64, blank=True, null=True, verbose_name='微信支付交易号')
    wechat_pay_openid = models.CharField(max_length=64, blank=True, null=True, verbose_name='微信支付用户openid')
    is_consumer_mini_program = models.BooleanField(default=True, verbose_name='是否来自消费者小程序')
    pay_params = models.JSONField(null=True, blank=True, help_text="支付参数")
    # 核心字段
    order_number = models.CharField(max_length=32, unique=True, db_index=True)
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
    payment_method = models.CharField(max_length=20, choices=PAYMENT_METHODS, blank=True)
    customer_contact_number = models.CharField(
        max_length=20, 
        null=True, 
        blank=True,
        verbose_name='虚拟联系方式'
    )
    special_requests = models.TextField(blank=True, null=True, verbose_name='特殊要求')
    is_accompany_meal = models.BooleanField(default=False, verbose_name="是否需要陪餐")
    # 金额字段
    subtotal = models.DecimalField(max_digits=10, decimal_places=2, validators=[MinValueValidator(0)],default=0)
    service_fee = models.DecimalField(max_digits=10, decimal_places=2, validators=[MinValueValidator(0)],default=0)
    total_amount = models.DecimalField(max_digits=10, decimal_places=2, validators=[MinValueValidator(0)],default=0)
    refund_status = models.CharField(
        max_length=20, 
        default='NONE',
        choices=[
            ('NONE', '无退款'),
            ('PROCESSING', '退款处理中'),
            ('SUCCESS', '退款成功'),
            ('FAILED', '退款失败')
        ]
    )
    out_refund_no = models.CharField(max_length=64, blank=True, null=True, verbose_name="退款单号")
    refund_amount = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name="退款金额")
    refund_time = models.DateTimeField(null=True, blank=True, verbose_name="退款时间")
    refund_reason = models.TextField(blank=True, null=True, verbose_name="退款原因")
    # 时间字段
    time_slot = models.ForeignKey(
        TimeSlot,
        on_delete=models.PROTECT,  # 防止删除已关联订单的档期
        related_name='timeslot_orders',     # 允许通过档期查询关联的订单
        related_query_name='timeslot_orders',
        verbose_name=_('预约档期')
    )
    booked_time = models.DateTimeField(null=True,verbose_name='预约时间')
    pay_time = models.DateTimeField(null=True)
    complete_time = models.DateTimeField(null=True)
    
    # 审计字段
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        indexes = [
            models.Index(fields=['order_number']),
            models.Index(fields=['-created_at']),
            models.Index(fields=['status', 'booked_time']),
        ]
        ordering = ['-created_at']

    def save(self, *args, **kwargs):
        """
        重写save方法，添加支付字段保护逻辑
        """
        # 1. 生成订单号（仅限新订单）
        if not self.order_number:
            self.order_number = OrderNumberGenerator.generate(self.customer_id)
        
        # 2. 仅当订单未支付且是微信小程序支付时，更新openid
        if (self.payment_method == 'wechat' 
            and self.is_consumer_mini_program 
            and self.status != 'paid'):  # 新增状态判断
            self.wechat_pay_openid = self.customer.wechat_openid
        
        # 3. 调用父类保存方法
        super().save(*args, **kwargs)

    from django.db import transaction  # 确保导入

    def change_status(self, to_status, changed_by=None, note='', request=None):
        """安全变更订单状态并自动记录日志"""
        from_status = self.status
        if from_status == to_status:
            return False

        # 关键修改：用事务包裹状态更新和后续操作
        with transaction.atomic():
            # 先更新状态
            self.status = to_status
            self.save(update_fields=['status', 'updated_at'])
            
            # 当订单变为已支付或已确认时，同步创建厨师端订单
            if to_status in ['paid', 'confirmed'] and not hasattr(self, 'chef_order'):
                # 获取服务时间
                if self.time_slot and hasattr(self.time_slot, 'date') and hasattr(self.time_slot, 'time'):
                    service_date = self.time_slot.date
                    service_time = self.time_slot.time
                elif self.booked_time:
                    service_date = self.booked_time.date()
                    service_time = self.booked_time.time()
                else:
                    now = timezone.now()
                    service_date = now.date()
                    service_time = now.time()

                # 计算厨师收入（确保 total_amount 是 Decimal）
                try:
                    if not isinstance(self.total_amount, Decimal):
                        self.total_amount = Decimal(str(self.total_amount))  # 最后兜底转换
                    chef_income = (self.total_amount * Decimal('0.8')).quantize(
                        Decimal('0.01'), 
                        rounding=ROUND_HALF_UP
                    )
                except InvalidOperation as e:
                    # 关键：如果计算出错，事务会回滚状态更新
                    logger.error(f"计算厨师收入失败: {str(e)}, total_amount={self.total_amount}")
                    raise  # 触发事务回滚

                # 创建厨师端订单
                try:
                    chef_order = DjChefOrder.objects.create(
                        chef=self.chef,
                        order_number=self.order_number,
                        customer=self.customer,
                        original_order=self,
                        service_date=service_date,
                        service_time=service_time,
                        service_address=str(self.address),
                        guest_count=self.guest_count if hasattr(self, 'guest_count') else 1,  # 确保有合理默认值
                        chef_fee=self.service_fee,
                        ingredients_fee=self.subtotal,
                        total_amount=self.total_amount,
                        special_requests=self.special_requests,
                        chef_income=chef_income
                    )
                    # 同步创建订单项
                    for item in self.items.all():
                        DjChefOrderItem.objects.create(
                            order=chef_order,
                            dish_id=item.dish_id,
                            name=item.name,
                            quantity=item.quantity,
                            price=item.price,
                            notes=item.order.special_requests
                        )
                except Exception as e:
                    logger.error(f"创建厨师端订单失败: {str(e)}")
                    raise  # 触发事务回滚

            from .signals import order_status_changed
            # 记录状态日志（放在事务内，确保状态变更和日志一致）
            OrderStatusLog.log_status_change( 
                order=self,
                to_status=to_status,
                changed_by=changed_by,
                note=note,
                from_status=from_status,
                request=request
            )
            # 发送信号
            order_status_changed.send( 
                sender=Order,
                order=self,
                to_status=to_status,
                changed_by=changed_by,
                note=note,
                from_status=from_status,
                request=request
            )
        return True

    def clean(self):
        """验证订单总金额"""
        if self.total_amount != self.subtotal + self.service_fee:
            raise ValidationError('订单总金额计算错误')


class OrderItem(models.Model):
    order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='items')
    dish_id = models.PositiveIntegerField()
    name = models.CharField(max_length=100)
    image = models.URLField(blank=True, null=True, verbose_name='菜品图片')
    quantity = models.PositiveIntegerField(validators=[MinValueValidator(1)])
    price = models.DecimalField(max_digits=10, decimal_places=2, validators=[MinValueValidator(0)])
    
    class Meta:
        unique_together = [['order', 'dish_id']]

    @property
    def total_price(self):
        return self.quantity * self.price


class OrderStatusLog(models.Model):
    """订单状态变更日志"""
    class StatusChoices(models.TextChoices):
        PENDING = 'pending', _('待处理')
        CONFIRMED = 'confirmed', _('已确认')
        PREPARING = 'preparing', _('准备中')
        COOKING = 'cooking', _('烹饪中')
        READY = 'ready', _('已就绪')
        DELIVERING = 'delivering', _('配送中')
        COMPLETED = 'completed', _('已完成')
        CANCELLED = 'cancelled', _('已取消')
        REFUNDED = 'refunded', _('已退款')

    order = models.ForeignKey(
        'Order',
        on_delete=models.CASCADE,
        related_name='status_logs',
        verbose_name=_('关联订单')
    )
    from_status = models.CharField(
        max_length=20,
        choices=StatusChoices.choices,
        verbose_name=_('原状态'),
        null=True,
        blank=True
    )
    to_status = models.CharField(
        max_length=20,
        choices=StatusChoices.choices,
        verbose_name=_('新状态')
    )
    changed_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        verbose_name=_('操作人')
    )
    note = models.TextField(
        max_length=500,
        blank=True,
        verbose_name=_('变更备注')
    )
    created_at = models.DateTimeField(
        auto_now_add=True,
        verbose_name=_('创建时间')
    )
    ip_address = models.GenericIPAddressField(
        null=True,
        blank=True,
        verbose_name=_('操作IP')
    )

    class Meta:
        verbose_name = _('订单状态日志')
        verbose_name_plural = _('订单状态日志')
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['order', 'created_at']),
        ]

    def __str__(self):
        return f"订单[{self.order.id}] {self.get_from_status_display() or 'N/A'} → {self.get_to_status_display()}"

    @classmethod
    def get_valid_transitions(cls):
        """获取合法的状态转换规则（供外部调用验证）"""
        return {
            # 待处理：用户刚下单未支付，可支付/取消；特殊场景下商家可直接确认（如免支付订单）
            'pending': ['paid', 'cancelled', 'confirmed'],  
            
            # 已支付：支付后可确认/取消（取消后通常触发退款）/直接退款
            'paid': ['confirmed', 'cancelled', 'refunded'],  
            
            # 已确认：（需处理退款逻辑）
            'confirmed': ['serving', 'cancelled'],
            
            'serving': ['completed'],
            
            # 已完成：仅支持退款（售后场景）
            'completed': ['refunded'],
            
            # 已取消：终态，无后续状态
            'cancelled': [],
            
            # 已退款：终态，无后续状态
            'refunded': []
        }

    @classmethod
    def log_status_change(cls, order, to_status, changed_by=None, note='', from_status=None, request=None):
        """创建状态变更日志的快捷方法"""
        valid_transitions = cls.get_valid_transitions()
        from_status = from_status or order.status
        if to_status not in valid_transitions.get(from_status, []):
            raise ValidationError(f'用户订单无法从 {from_status} 状态变更为 {to_status} 状态')

        return cls.objects.create(
            order=order,
            from_status=from_status,
            to_status=to_status,
            changed_by=changed_by,
            note=note,
            ip_address=request.META.get('REMOTE_ADDR') if request else None
        )


# 厨师服务端模型
class DjChefOrder(models.Model):
    """厨师端订单模型"""
    STATUS_CHOICES = (
        ('pending', '待确认'),
        ('confirmed', '已确认'),
        ('serving', '服务中'),
        ('completed', '已完成'),
        ('cancelled', '已取消'),
    )
    
    # 关系字段
    chef = models.ForeignKey(
        DjChef,
        on_delete=models.PROTECT,
        related_name='chef_orders',
        verbose_name='关联厨师'
    )
    customer = models.ForeignKey(
        User,
        on_delete=models.PROTECT,
        related_name='chef_orders',
        verbose_name='关联顾客'
    )
    original_order = models.OneToOneField(
        'orders.Order',
        on_delete=models.PROTECT,
        related_name='chef_order',
        verbose_name='原始订单'
    )
    
    # 核心字段
    order_number = models.CharField(
        max_length=32,
        unique=True,
        db_index=True,
        verbose_name='订单编号'
    )
    status = models.CharField(
        max_length=20,
        choices=STATUS_CHOICES,
        default='pending',
        verbose_name='订单状态'
    )
    
    # 服务信息（可考虑通过 original_order.time_slot 关联，此处保留业务字段）
    service_date = models.DateField(verbose_name='服务日期')
    service_time = models.TimeField(verbose_name='服务时间')
    service_address = models.TextField(verbose_name='服务地址')
    guest_count = models.PositiveSmallIntegerField(
        default=1,
        verbose_name='用餐人数'
    )
    
    # 金额字段（厨师视角）
    chef_fee = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        validators=[MinValueValidator(0)],
        verbose_name='厨师服务费'
    )
    ingredients_fee = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        validators=[MinValueValidator(0)],
        verbose_name='食材费用'
    )
    total_amount = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        validators=[MinValueValidator(0)],
        verbose_name='总金额'
    )
    chef_income = models.DecimalField(
        verbose_name="厨师收入",
        default=0,
        max_digits=10,
        decimal_places=2
    )
    special_requests = models.TextField(blank=True, null=True, verbose_name='订单要求')
    
    # 时间字段
    confirmed_at = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name='确认时间'
    )
    completed_at = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name='完成时间'
    )
    
    # 审计字段
    created_at = models.DateTimeField(
        auto_now_add=True,
        verbose_name='创建时间'
    )
    updated_at = models.DateTimeField(
        auto_now=True,
        verbose_name='更新时间'
    )
    
    class Meta:
        verbose_name = '厨师订单'
        verbose_name_plural = '厨师订单'
        indexes = [
            models.Index(fields=['order_number']),
            models.Index(fields=['-created_at']),
            models.Index(fields=['status', 'service_date']),
        ]
        ordering = ['-service_date', '-service_time']
    
    def __str__(self):
        return f"厨师订单 #{self.order_number} ({self.get_status_display()})"
    
    def save(self, *args, **kwargs):
        self.full_clean()
        """自动生成订单号"""
        if not self.order_number:
            from django.utils import timezone
            date_str = timezone.now().strftime('%Y%m%d')
            today_count = DjChefOrder.objects.filter(
                chef=self.chef,
                created_at__date=timezone.now().date()
            ).count() + 1
            try:
                self.order_number = f'CHEF{date_str}{self.chef_id}{today_count:03d}'
            except AttributeError:
                raise ValidationError('厨师或顾客ID无效')
        super().save(*args, **kwargs)
    
    def change_status(self, to_status, changed_by=None, note=''):
        """
        安全变更订单状态并记录日志（添加状态转换验证）
        """
        from_status = self.status
        
        if from_status != to_status:
            # 验证状态转换合法性
            valid_transitions = self.get_valid_transitions()
            if to_status not in valid_transitions.get(from_status, []):
                raise ValidationError(f'厨师订单无法从 {from_status} 变更为 {to_status}')
            
            self.status = to_status
            self.save(update_fields=['status', 'updated_at'])
            
            # 记录状态变更日志
            DjChefOrderStatusLog.objects.create(
                order=self,
                from_status=from_status,
                to_status=to_status,
                changed_by=changed_by,
                note=note
            )
            
            # 触发状态变更信号（用于同步用户订单）
            from .signals import chef_order_status_changed
            chef_order_status_changed.send(
                sender=self.__class__,
                chef_order=self,
                from_status=from_status,
                to_status=to_status
            )
            return True
        return False

    @classmethod
    def get_valid_transitions(cls):
        """获取合法的状态转换规则（供外部调用验证）"""
        return {
            # 待处理：用户刚下单未支付，可支付/取消；特殊场景下商家可直接确认（如免支付订单）
            'pending': ['paid', 'cancelled', 'confirmed'],  
            
            # 已支付：支付后可确认/取消（取消后通常触发退款）/直接退款
            'paid': ['confirmed', 'cancelled', 'refunded'],  
            
            # 已确认：（需处理退款逻辑）
            'confirmed': ['serving', 'cancelled'],

            'serving': ['completed'],
            
            # 已完成：仅支持退款（售后场景）
            'completed': ['refunded'],
            
            # 已取消：终态，无后续状态
            'cancelled': [],
            
            # 已退款：终态，无后续状态
            'refunded': []
        }


class DjChefOrderItem(models.Model):
    """厨师订单菜品项"""
    order = models.ForeignKey(
        DjChefOrder,
        on_delete=models.CASCADE,
        related_name='items',
        verbose_name='关联订单'
    )
    dish_id = models.PositiveIntegerField(verbose_name='菜品ID')
    name = models.CharField(max_length=100, verbose_name='菜品名称')
    quantity = models.PositiveIntegerField(
        validators=[MinValueValidator(1)],
        verbose_name='数量'
    )
    price = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        validators=[MinValueValidator(0)],
        verbose_name='单价'
    )
    notes = models.TextField(
        null=True,
        blank=True,
        verbose_name='特殊要求'
    )
    
    class Meta:
        verbose_name = '厨师订单菜品'
        verbose_name_plural = '厨师订单菜品'
        unique_together = [['order', 'dish_id']]
    
    def __str__(self):
        return f"{self.name} x{self.quantity}"
    
    @property
    def total_price(self):
        return self.quantity * self.price


class DjChefOrderStatusLog(models.Model):
    """厨师订单状态变更日志"""
    order = models.ForeignKey(
        DjChefOrder,
        on_delete=models.CASCADE,
        related_name='status_logs',
        verbose_name='关联订单'
    )
    from_status = models.CharField(
        max_length=20,
        choices=DjChefOrder.STATUS_CHOICES,
        verbose_name='原状态',
        null=True,
        blank=True
    )
    to_status = models.CharField(
        max_length=20,
        choices=DjChefOrder.STATUS_CHOICES,
        verbose_name='新状态'
    )
    changed_by = models.ForeignKey(
        DjChef,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        verbose_name='操作人'
    )
    note = models.TextField(
        blank=True,
        verbose_name='变更备注'
    )
    created_at = models.DateTimeField(
        auto_now_add=True,
        verbose_name='创建时间'
    )
    
    class Meta:
        verbose_name = '厨师订单状态日志'
        verbose_name_plural = '厨师订单状态日志'
        ordering = ['-created_at']
    
    def __str__(self):
        return f"订单[{self.order.id}] {self.get_from_status_display() or 'N/A'} → {self.get_to_status_display()}"


class DjChefReview(models.Model):
    """厨师评价模型（只读，厨师端只能查看）"""
    RATING_CHOICES = [
        (1, '1星 - 很差'),
        (2, '2星 - 一般'),
        (3, '3星 - 满意'),
        (4, '4星 - 很好'),
        (5, '5星 - 非常棒'),
    ]
    
    chef = models.ForeignKey(
        DjChef,
        on_delete=models.CASCADE,
        related_name='chef_reviews',
        verbose_name='关联厨师'
    )
    customer = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        verbose_name='评价顾客'
    )
    order = models.OneToOneField(
        DjChefOrder,
        on_delete=models.CASCADE,
        related_name='review',
        verbose_name='关联订单'
    )
    
    # 评分
    overall_rating = models.PositiveSmallIntegerField(
        choices=RATING_CHOICES,
        verbose_name='总体评分'
    )
    taste_rating = models.PositiveSmallIntegerField(
        choices=RATING_CHOICES,
        verbose_name='口味评分'
    )
    service_rating = models.PositiveSmallIntegerField(
        choices=RATING_CHOICES,
        verbose_name='服务评分'
    )
    punctuality_rating = models.PositiveSmallIntegerField(
        choices=RATING_CHOICES,
        verbose_name='守时评分'
    )
    
    # 评价内容
    comment = models.TextField(
        blank=True,
        verbose_name='评价内容'
    )
    
    # 元数据
    is_anonymous = models.BooleanField(
        default=False,
        verbose_name='匿名评价'
    )
    created_at = models.DateTimeField(
        auto_now_add=True,
        verbose_name='评价时间'
    )
    
    class Meta:
        verbose_name = '厨师评价'
        verbose_name_plural = '厨师评价'
        ordering = ['-created_at']
    
    def __str__(self):
        return f"{self.order.order_number} 的评价 ({self.get_overall_rating_display()})"
    
    @property
    def average_rating(self):
        """计算平均评分"""
        return round((self.overall_rating + self.taste_rating + self.service_rating + self.punctuality_rating) / 4, 1)